#ifndef __LIST__INCLUDED__
#define __LIST__INCLUDED__

#include "le.h"
#include <cstddef>

using namespace std;

template < class type >

class List {
	LE<type>*  first;
	LE<type>*  last;
	int        size;

public:
	/**
	  * Creates an empty list.
	  */
	List() {
		first = last = NULL;
		size = 0;
	}

	bool isEmpty() {
		if(this->size == 0)
			return true;
		else
			return false;
	}
	
	LE<type>* getFirst() {
		return this->first;
	}

	/**
	  * Appends a new value to the end of the list.
	  * @param value New value to add.
	  */
	void append(type* value) {
		// 1. Create new list element
		LE<type>* lastLE = new LE<type>(value, last);

		// List empty?
		if (size == 0) {
			// Add new list element as first and last element.
			first = lastLE;
		}

		// List is not empty
		else {
			// 2. Neues LE mit letztem LE verbinden
			last->setNext(lastLE);
		}
		// 3. Neues LE als letztes Element eintragen
		last = lastLE;
		// Increase number of elements
		size++;
	}

	// Destruktor
	~List() {
		LE<type>* currentDel = first;
		LE<type>* nextDel    = NULL;
		while (currentDel != NULL) {
			nextDel = currentDel->getNext();
			delete currentDel;
			currentDel = nextDel;
		}
	}
	
	/**
	* Iterator
	* @author: Christoph Ehscheidt
	*/ 
	class Iterator {		
		LE<type>* currentElement;
	
	public:
		friend class List;
		
		Iterator(LE<type>* init = NULL){
			this->currentElement = init;
		}
		Iterator(const List& L)  {
			*this = L.begin();
		}
		
		/**
		* Returns the data
		*/
		type* operator*() const{
			return this->currentElement->getValue();
		}
		
		/**
		* Compares two iterators (==)
		*/
		bool operator==(const Iterator& x) const {
			return this->currentElement == x.currentElement;
		}
		
		/**
		* Compares two iterators (!=)
		*/
		bool operator!=(const Iterator& x) const {
			return this->currentElement != x.currentElement;
		}
		
		/**
		* Returns the current LE
		*/
		LE<type>* getCurrentElement() {
			return this->currentElement;
		}
		
		/**
		* Set the current LE
		*/
		void setCurrentElement(LE<type>* el) {
			this->currentElement = el;
		}
	
		/**
		* Post-Increment
		*/
		Iterator* operator++()  {
			if(this->currentElement) {
				this->currentElement = this->currentElement->getNext();
			}
	
			return this;
		}
		
		/**
		* Pre-Increment
		*/
		Iterator* operator++(int) {
			Iterator* temp = this;
			++*this;
			return temp;
		}
		
		
	
	
	};
	
	/**
	* Removes a LE. 
	* @param iter Element which should be removed.
	* @return bool True if removal had success
	*
	*/
	bool remove(Iterator* iter) {
		LE<type>* current = iter->getCurrentElement();
		LE<type>* prev = current->getPrev();
		LE<type>* next = current->getNext();
		
		bool done = false;
		
		if(next && !prev) {
			this->first = next;
			iter->setCurrentElement(this->first);
			done = true;
		}
		
		if(!next && prev) {
			this->last = prev;
			iter->setCurrentElement(this->last);
			done = true;
		}
		
		if(!next && !prev) {
			this->first = this->last = NULL;
			iter->setCurrentElement(NULL);
			done = true;
		}
		
		if(next && prev) {
		
			prev->setNext(next);
			next->setPrev(prev);
						
			iter->setCurrentElement(prev);
			done = true;
		
		}
		
		if(done) {
			delete current;
			this->size--;
		}
		
		return done;
	}
	
	/**
	* Returns a Iterator, pointing to the begin of the list
	* @return Iterator
	*/
	Iterator begin() const {
		return Iterator(this->first);
	}
	
	/**
	* Returns a Iterator, pointing to the end of the list
	* @return Iterator
	*/
	Iterator end() const {
		return Iterator();
	}
};
#endif // __LIST__INCLUDED__
